package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.*;
import com.sc.nft.entity.vo.*;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.IncomeService;
import com.sc.nft.service.ScOrderSettleService;
import com.sc.nft.service.SecondOrderService;
import com.sc.nft.service.UserWalletService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 二级订单表服务接口实现
 *
 * @author kancy
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2022-10-05 12:53:07
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SecondOrderServiceImpl implements SecondOrderService {

    private final SecondOrderDao secondOrderDao;

    private final SecondCollectionDao secondCollectionDao;

    private final UserWalletService userWalletService;

    private final DigitalCollectionDao digitalCollectionDao;

    private final UserInfoDao userInfoDao;

    private final UserWalletDao userWalletDao;
    private final UserWalletDetailDao userWalletDetailDao;
    private final ExpenditureRecordDao expenditureRecordDao;

    private final PrivilegeDao privilegeDao;
    private final IncomeService incomeService;
    private final FilterIncomeListDao filterIncomeListDao;

    private final RedisTemplate redisTemplate;
    private final DaoDivideInfoDao daoDivideInfoDao;
    private final ShareProfitDao shareProfitDao;
    private final ShareProfitPanelDao shareProfitPanelDao;
    private final ScOrderSettleService orderSettleService;
    private final PayOrderDao payOrderDao;
    private final PayOrderItemDao payOrderItemDao;


    @Override
    public void unfreeze(String userTel) throws GlobalRunTimeException {
        UserInfo oneByUserTel = userInfoDao.getOneByUserTel(userTel);
        if (BeanUtil.isEmpty(oneByUserTel)) {
            throw new GlobalRunTimeException("用户不存在");
        }
//        secondOrderDao.unfreeze(oneByUserTel.getId());
        String key = RedisKeyEnum.SECOND_USER_LOCK.getKey() + oneByUserTel.getId();
        if (!redisTemplate.hasKey(key)) {
            throw new GlobalRunTimeException("没有需要解锁的数据");
        }
        redisTemplate.delete(key);
    }

    /**
     * 获取用户当天被锁数据
     *
     * @param userTel
     * @return
     */
    @Override
    public AdminSecondOrderNowDataLockVO nowDataLockOrderSize(String userTel) {
        UserInfo oneByUserTel = userInfoDao.getOneByUserTel(userTel);
        if (BeanUtil.isEmpty(oneByUserTel)) {
            throw new GlobalRunTimeException("用户不存在");
        }
        return secondOrderDao.nowDataLockOrderSize(oneByUserTel.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void extracted(SecondOrder secondOrder) {
        List<SettleAmountDTO> amountDTOS = new ArrayList<>();
        /**
         *  根据支付单支付方式决定资金走向 因所有方式付款都有支付单，走到这的订单都会有支付单 暂不做非空判断 后续特殊情况再看
         */
        PayOrder payOrder = payOrderItemDao.getByOrderIdAndType(secondOrder.getId(), SecondPayOrderItemTypeEnum.COLLECTION, PayTypeEnum.SECOND);
        SecondCollection secondCollection = secondCollectionDao.getById(secondOrder.getSecondCollectionId());
        Boolean counterKnock = Boolean.FALSE;
        Boolean buy = Boolean.FALSE;
        Boolean sale = Boolean.FALSE;
        if (MarketTypeEnum.FREE_MARKET == secondCollection.getMarketType()) {//自由市场
            DigitalCollection digitalCollection = digitalCollectionDao.getById(secondCollection.getCollectionId());
            DaoDivideInfo divideInfo = daoDivideInfoDao.getDivideInfoByDaoId(digitalCollection.getUserCreatorId());
            if (ObjectUtil.isNotNull(divideInfo) && divideInfo.getStatus()) {//并且开启了分成
                buy = filterIncomeListDao.checkIsFilterAccount(digitalCollection.getUserCreatorId(), secondOrder.getBuyUserId());
                sale = filterIncomeListDao.checkIsFilterAccount(digitalCollection.getUserCreatorId(), secondOrder.getSalesUserId());
                counterKnock = buy && sale;
                if (counterKnock) {//确认是市值对敲
                    secondOrder.setCharge(BigDecimal.ZERO);
                }
            }
        }

        // 订单手续费
        BigDecimal charge = BigDecimal.ZERO;
        if (secondCollection.getMarketType().equals(MarketTypeEnum.BRAND_INCUBATION)) {
            charge = secondOrder.getCharge().add(secondOrder.getPreventHoard());
        } else {
            charge = secondOrder.getCharge();
        }
        // 把钱给寄售人,付款金额减去利息 TODO 连连支付把各分账对象组装到一起 其他的走原逻辑  卖家是市值账号收款走假钱包
        //货款

        if (payOrder.getChannel().equals(PayChannelEnum.LL_PAY) && !filterIncomeListDao.getIsContainsUserId(secondOrder.getSalesUserId())) {
            BigDecimal goodsAmount = secondOrder.getBuyPrice().subtract(charge).subtract(secondOrder.getGas());
            SettleAmountDTO amountDTO = new SettleAmountDTO();
            amountDTO.setUserId(secondOrder.getSalesUserId());
            amountDTO.setAmount(goodsAmount);
            amountDTO.setWalletDetailTypeEnum(WalletDetailTypeEnum.SECOND_SALE);
            amountDTO.setExpenditureRecordTypeEnum(ExpenditureRecordTypeEnum.SELL);
            amountDTOS.add(amountDTO);
        } else {
            userWalletService.addIncomeRemit(secondOrder.getSalesUserId(), secondOrder.getOrderNo(),
                    secondOrder.getBuyPrice(), charge, secondOrder.getGas(), WalletDetailTypeEnum.SECOND_SALE,
                    ExpenditureRecordTypeEnum.SELL);
        }


        // 寄售人
        Long salesUserId = secondOrder.getSalesUserId();
        // 确定用户是否有指定的特权藏品,特权藏品需要计算获取对应的特权.如果没有就算了.
        // 有特权藏品的话,要把利息返回给部分给用户
        UserInfo shellUserInfo = userInfoDao.getById(salesUserId);
        Privilege byUserLevel = privilegeDao.getByUserLevel(shellUserInfo.getPrivilegeLevel());
        if (!BeanUtil.isEmpty(byUserLevel)) {

            // 如果bean对象不为空,计算对应的返现
            if (byUserLevel.getConsignmentSalesDiscount() != null && byUserLevel.getConsignmentSalesDiscount().compareTo(BigDecimal.ZERO) == 1) {
                UserWallet upUserWallet = userWalletDao.getByUserId(shellUserInfo.getId());
                // 用户返现金额
                BigDecimal userConsignmentSalesDiscount = secondOrder.getCharge().multiply(byUserLevel.getConsignmentSalesDiscount()).setScale(2, BigDecimal.ROUND_DOWN);
                // 把返现金额给用户
                userWalletDao.addPayBalance(shellUserInfo.getId(), userConsignmentSalesDiscount);

                UserWalletDetail userWalletDetail = new UserWalletDetail();
                userWalletDetail.setUserId(shellUserInfo.getId());
                userWalletDetail.setType(WalletDetailTypeEnum.CONSIGNMENT_SALES_DISCOUNT);
                userWalletDetail.setBalanceType(UserBalanceTypeEnum.PAY_BALANCE);
                userWalletDetail.setAmount(userConsignmentSalesDiscount);
                userWalletDetail.setCharge(BigDecimal.ZERO);
                userWalletDetail.setRealAmount(userConsignmentSalesDiscount);
                userWalletDetail.setAfterBalance(upUserWallet.getPayBalance().add(userConsignmentSalesDiscount));
                userWalletDetail.setBeforeBalance(upUserWallet.getPayBalance());
                userWalletDetail.setIsAdd(Boolean.TRUE);
                userWalletDetail.setRemark(WalletDetailTypeEnum.CONSIGNMENT_SALES_DISCOUNT.getDescription());
                userWalletDetailDao.insert(userWalletDetail);

                ExpenditureRecord expenditureRecord = new ExpenditureRecord();
                expenditureRecord.setRemark("手续费返现");
                expenditureRecord.setUserId(shellUserInfo.getId());
                expenditureRecord.setAmount(userConsignmentSalesDiscount);
                expenditureRecord.setCharge(BigDecimal.ZERO);
                expenditureRecord.setRealAmount(userConsignmentSalesDiscount);
                expenditureRecord.setType(ExpenditureRecordTypeEnum.RED_PACKET);
                expenditureRecord.setBeforeBalance(upUserWallet.getPayBalance());
                expenditureRecord.setAfterBalance(upUserWallet.getPayBalance().add(userConsignmentSalesDiscount));
                expenditureRecord.setOrderId(secondOrder.getSecondCollectionId());
                expenditureRecordDao.insert(expenditureRecord);
            }
        }
        //直推
        if (!filterIncomeListDao.getIsContainsUserId(secondOrder.getBuyUserId())) {
//            log.info("1-进入二级藏品直推奖励，订单：{}", JSONObject.toJSONString(secondOrder));
            if (payOrder.getChannel().equals(PayChannelEnum.LL_PAY)) {
                incomeService.secondDirectPushIncomeForSplit(secondOrder, amountDTOS);
            } else {
//                log.info("非连连支付二级藏品订单，进入原结算逻辑:{}", JSONObject.toJSONString(secondOrder));
                incomeService.secondDirectPushIncome(secondOrder);
            }

        }
        secondOrderDao.allReadySettleFlag(secondOrder.getId());
        if (MarketTypeEnum.FREE_MARKET == secondCollection.getMarketType()) {//自由市场
            DigitalCollection digitalCollection = digitalCollectionDao.getById(secondCollection.getCollectionId());
            DaoDivideInfo divideInfo = daoDivideInfoDao.getDivideInfoByDaoId(digitalCollection.getUserCreatorId());
            if (ObjectUtil.isNotNull(divideInfo) && divideInfo.getStatus()) {                //并且开启了分成
                //如果手续费超出4位  则计算没什么意义
                if (NumberUtil.isGreater(BigDecimal.ZERO, secondCollection.getCharge().setScale(4, BigDecimal.ROUND_DOWN))) {
                    return;
                }

                /*
                 * 品牌旗下市值对敲(市值账号互相交易)不产生手续费
                 * 2、品牌旗下市值账号为买/卖任意一方时，品牌方按上方配置比例参与手续费返点：品牌手续费返点收益=藏品交易金额*自由市场手续费率*(100%-直推分红比) * 品牌方分成比例
                 * 买卖双方均非品牌旗下市值账号时，品牌方不参与手续费分润
                 * */
                // 分润的钱
                BigDecimal returnPrice = BigDecimal.ZERO;
                // 当前不是市值对敲
                if (!counterKnock) {
                    // 购买方是市值或者卖方是市值
                    if ((buy && !sale) || (!buy && sale)) {
                        // 计算分润的钱
                        // 获取直推分润收益
                        ShareProfitPanel panel = shareProfitPanelDao.getById(secondOrder.getShareProfitPanelId());
                        if (BeanUtil.isEmpty(panel)) {
                            return;
                        }
                        List<ShareProfit> shareProfitList = shareProfitDao.getByPanelIdAndType(panel.getId(), DivideTypeEnum.DIRECT_PUSH);
                        if (CollUtil.isEmpty(shareProfitList)) {
                            return;
                        }
                        // shareProfitList集合中的sumRatio字段进行相加
                        BigDecimal sumRatio = shareProfitList.stream().map(ShareProfit::getSumRatio).reduce(BigDecimal.ZERO, BigDecimal::add);
                        // 如果大于1了,那么就给1
                        if (NumberUtil.isGreater(sumRatio, BigDecimal.ONE)) {
                            sumRatio = BigDecimal.ONE;
                        }
                        returnPrice = secondOrder.getCharge().multiply(BigDecimal.ONE.subtract(sumRatio)).multiply(divideInfo.getShareRatio().divide(Convert.toBigDecimal(100).setScale(2, BigDecimal.ROUND_DOWN))).setScale(2, BigDecimal.ROUND_DOWN);
                    }
                }
                //返点金额
                if (NumberUtil.isGreater(returnPrice, BigDecimal.ZERO)) {
                    userWalletService.addIncome(divideInfo.getReturnUserId(), secondOrder.getOrderNo(), returnPrice, BigDecimal.ZERO, WalletDetailTypeEnum.DAO_CHARGE_SHARE, ExpenditureRecordTypeEnum.CHARGE_RETURN, "自由市场{" + digitalCollection.getFirstTitle() + "}");
                }
            }
        }
        //TODO 批量生成结算单
        if (!amountDTOS.isEmpty()) {
            batchCreateSettleOrder(amountDTOS, secondOrder, payOrder);
        }

        log.info("二级市场直推收益:直推收益结算完毕");
    }

    //TODO 填充结算单数据 生成结算单
    private void batchCreateSettleOrder(List<SettleAmountDTO> settleAmountDTOS, SecondOrder order, PayOrder payOrder) {
//        log.info("二级结算组装的分润对象：{}", JSONArray.toJSONString(settleAmountDTOS));
        //连连走分账
        if (payOrder.getChannel().equals(PayChannelEnum.LL_PAY)) {
            //用户分账金额总和
            BigDecimal userSettleAmount = BigDecimal.ZERO;
            for (SettleAmountDTO settleAmountDTO : settleAmountDTOS) {
                if (ObjectUtil.isNotNull(settleAmountDTO.getUserIncomeRecord())) {
                    //保存数据 属于分润性质的都会有记录
                    settleAmountDTO.getUserIncomeRecord().insert();
                }
                orderSettleService.create(order.getId(), order.getBuyPrice(), order.getOrderNo(), settleAmountDTO.getUserId(), payOrder, settleAmountDTO.getWalletDetailTypeEnum(),
                        settleAmountDTO.getAmount(), SettleUserTypeEnum.USER, settleAmountDTO.getExpenditureRecordTypeEnum(), BizTypeEnum.COLLECTION, MarketLevelEnum.SECOND);
                userSettleAmount = userSettleAmount.add(settleAmountDTO.getAmount());
            }
            //TODO 订单剩余未分金额归平台 购买金额-用户分账金额=平台所得金额 此处只管卖家付款金额和直推 其他全是平台的
            BigDecimal lessAmount = order.getBuyPrice().subtract(userSettleAmount);
            //TODO 给平台增加待结算 有结余才算否则无意义
            if (lessAmount.compareTo(BigDecimal.ZERO) > 0) {
                orderSettleService.create(order.getId(), order.getBuyPrice(), order.getOrderNo(), null, payOrder, WalletDetailTypeEnum.PLANT_LESS,
                        lessAmount, SettleUserTypeEnum.MERCHANT, ExpenditureRecordTypeEnum.PLANT_AMOUNT, BizTypeEnum.COLLECTION, MarketLevelEnum.SECOND);
            }
        }

    }

    @Override
    public Page<SecondOrderDTO> adminPage(Date startTime, Date endTime, String buyUserTel, String saleUserTel, Integer marketType, String firstTitle, int pageNo, int pageSize) {
        Page<SecondOrderDTO> result = new Page<>();
        Long buyUserId = null;
        Long saleUserId = null;
        Long collectionId = null;
        if (StrUtil.isNotBlank(buyUserTel)) {
            UserInfo buyUser = userInfoDao.getOneByUserTel(buyUserTel);
            buyUserId = ObjectUtil.isNull(buyUser) ? null : buyUser.getId();
        }
        if (StrUtil.isNotBlank(saleUserTel)) {
            UserInfo saleUser = userInfoDao.getOneByUserTel(saleUserTel);
            saleUserId = ObjectUtil.isNull(saleUser) ? null : saleUser.getId();
        }
        if (StrUtil.isNotBlank(firstTitle)) {
            DigitalCollection byTitle = digitalCollectionDao.getByTitle(firstTitle);
            collectionId = byTitle.getId();
        }
        Page<Long> idPage = secondOrderDao.idPage(buyUserId, saleUserId, collectionId, startTime, endTime, marketType, pageNo, pageSize);
        BeanUtil.copyProperties(idPage, result);
        if (CollUtil.isEmpty(idPage.getRecords())) {
            return result;
        }
        List<SecondOrderDTO> secondOrderList = secondOrderDao.adminPageByIdList(idPage.getRecords());
        result.setRecords(secondOrderList);
        return result;
    }

    @Override
    public List<SecondOrderCollectionListDTO> collectionList(Integer marketType) {
        return secondOrderDao.collectionList(marketType);
    }

    @Override
    public List<SecondOrderExportListVO> collectionExport(List<Long> collectionIdList, Integer marketType, Date startTime, Date endTime) {
        return secondOrderDao.getListByCollectionIdAndTime(collectionIdList, marketType, startTime, endTime);
    }


    @Override
    public List<DingLianDealPracticalVO> dealPracticalInConsensus() {
        return secondOrderDao.dealPracticalInConsensus();
    }

    @Override
    public List<DingLianDealPracticalVO> dealPracticalNotInConsensus() {
        return secondOrderDao.dealPracticalNotInConsensus();
    }

    @Override
    public List<DingLianTransactionRecordVO> transactionRecord(DingLianTransactionRecordDTO dto) {
        return secondOrderDao.transactionRecord(dto);
    }

    @Override
    public List<ConsignmentRecordVO> consignmentRecord(ConsignmentRecordDTO dto) {
        // 获取藏品id,直接通过名字获取挂售列表.成本很高.
        DigitalCollection byFirstTitle = digitalCollectionDao.getByFirstTitle(dto.getAlbumName());
        // 通过寄售列表,获取集合 排序挂单时间
        if (byFirstTitle.getCollectionType() == DigitalMarketTypeEnum.ECOLOGY) {
            return secondOrderDao.consignmentRecordForConsensus(byFirstTitle.getId(), dto.getLimit());
        } else {
            return secondOrderDao.consignmentRecord(byFirstTitle.getId(), dto.getLimit());
        }
    }

    @Override
    public List<ZhiTanTradeVO> tradeList(Integer startTime, Integer limit) {
        //传入时间是秒 *1000转为毫秒计算
        Long minSecond = (long) (startTime * 1000L);
        DateTime date = DateUtil.date(minSecond);
        List<Long> idList = secondOrderDao.tradeIdList(date, limit);
        if (CollUtil.isEmpty(idList)) {
            return new ArrayList<>();
        }
        return secondOrderDao.tradeList(idList);
    }

    @Override
    public Integer countOrder(Long userId) {
//        LambdaQueryWrapper<SecondOrder> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.eq(SecondOrder::getBuyUserId, userId);
//        queryWrapper.eq(SecondOrder::getStatus, OrderStatusEnum.PAYMENT);
//        queryWrapper.last(" limit 5");
//        return secondOrderDao.list(queryWrapper).size();

        return secondOrderDao.countOrder(userId);
    }

}